package hhf.flex.ascreator.patterns;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.Set;

public class ASDelayedFunctionPattern {
    /*
     * 
     *    !!!!!
     * TODO  : cas ou les paramètres sont des List =>
     *OneToMany
     * 
     * 
     * 
     */

    public static void writeFunction(OutputStreamWriter out, String pack, String className, String service, String argsTyped, Set<String> imports, Method method) throws IOException {
        out.write("package " + pack + " {\n");
        out.write("\n");
        out.write("\timport hhf.services.entities.AbstractDelayedFunction;\n");
        for (String imp : imports) {
            String first = imp.split("\\.")[0];
            if (!((first.equals("mx")) || (first.equals("flex")))) {
                out.write("\timport " + imp + ";\n");
            }
        }
        out.write("\n");
        out.write("\t[Bindable]\n");
        out.write("\t[Entity]\n");
        out.write("\t[Table(name=\"" + method.getDeclaringClass().getSimpleName() + "_" + className + "\")]\n");
        out.write("\tpublic class " + className + " extends AbstractDelayedFunction {\n");
        out.write("\n");

        String constructorBody = "";
        String[] argsTypedTab = argsTyped.split(",");
        for (String argTyped : argsTypedTab) {
            out.write("\n\t\t[ManyToOne(cascade=\"ALL\")]\n");
            //voir si ce n'est pas mieux de laisser des arg0, arg1... pour l'ordre 
            //des paramètres à l'appel.
            out.write("\t\tpublic var " + argTyped + ";\n");

            //pour le constructeur juste en dessous..
            constructorBody += "\t\t\tthis." + argTyped.split(":")[0] + " = " + argTyped.split(":")[0] + ";\n";

        }
        out.write("\n");
        out.write("\t\tpublic function " + className + "() {\n");
        //out.write(constructorBody);
        //out.write("\t\t\tsuper(\"" + pack + "." + service + "\", new Date());\n");
        out.write("\t\t}\n");

        out.write("\n\t\tpublic function init(" + argsTyped + "):void {\n");
        out.write(constructorBody);
        out.write("\t\t\tthis.service = \"" + pack + "." + service + "\";\n");
        //out.write("\t\t\tthis.transfertDate = new Date();\n");
        out.write("\t\t}\n");

        out.write("\t}\n");
        out.write("\t\n");
        out.write("\t\n");
        out.write("}\n");
    }

    //TODO ecrire cela dans une class spéciale. 
    // appel de TOUS les delay et pas seulement ceux de la class concernées.. ce qui est le cas
    // avec cette version de la fonction writeLaunch.
    // piste : méthode en static appelée en passant en paramètre l'entityManager.
    // on retrouve les class des service grace à la base
    /**
     * Ecrit la fonction qui permet l'appel des appels serveur mis en attente
     * dans la base locale.
     * @param out
     * @param pack
     * @param className
     * @param service
     * @param argsTyped
     * @param imports
     * @param method
     * @throws IOException 
     */
    public static void writeLaunch(OutputStreamWriter out, String pack, String className, String service, String argsTyped, Set<String> imports, Method method) throws IOException {
        out.write("\t\t/**\n");
        out.write("\t\t * Fonction qui permet le lancement des appels serveur mis en attente.\n");
        out.write("\t\t * Sera appelée à la reconnexion avec le serveur.\n");
        out.write("\t\t */\n");
        out.write("\t\tpublic function launchDelayedServices():void {\n");
        out.write("\t\t\t//on récupère les appels en base \n");
        out.write("\t\t\tvar cb:CriteriaBuilder = em.getCriteriaBuilder();  \n");
        out.write("\t\t\tvar  query:CriteriaQuery = cb.createQuery(" + className + "Delayed);  \n");
        out.write("\t\t\tquery.from(" + className + "Delayed);  \n");
        out.write("\t\t\tvar tq:Query = em.createTypedQuery(query);  \n");
        out.write("\t\t\tvar delayedCalls:Array = tq.getResultList() as Array;\n");
        out.write("\t\t\t \n");
        out.write("\t\t\t//parcour des résultats et appels \n");
        out.write("\t\t\tif(delayedCalls != null){ \n");
        out.write("\t\t\t\tfor each(var delayedCall:" + className + "Delayed in delayedCalls) { \n");
        String args = "";
        if (argsTyped != null) {
            String[] arguments = argsTyped.split(",");
            if (arguments != null) {
                for (String argument : arguments) {
                    //todo : match regex					
                    String[] decomp = argument.split(":");
                    out.write("\t\t\t\t\tvar " + decomp[0].replace(" ", "") + "Tmp : " + decomp[1] + " = delayedCall." + decomp[0].replace(" ", "") + ";\n");
                    if (!args.equals("")) {
                        args += ", ";
                    }
                    args += decomp[0] + "Tmp";
                }
            }
        }
        out.write("\t\t\t\t\tthis.send(" + args + ");\n");
        out.write("\t\t\t\t\tem.remove(delayedCall); \n");
        out.write("\t\t\t\t} \n");
        out.write("\t\t\t}\n");
        out.write("\t\t}\n  ");

    }

    public static void writeCheckDelayedServices(OutputStreamWriter out) throws IOException {
        out.write("\t\t/**      \n");
        out.write("\t\t * Fonction qui lance les fonctions DELAYED \n");
        out.write("\t\t */     \n");
        out.write("\t\tpublic function checkDelayedServices():void { \n");
        out.write("\t\t\tif(NetworkMonitor.available) {");
        out.write("\t\t\t\tvar cb:CriteriaBuilder = em.getCriteriaBuilder();\n");
        out.write("\t\t\t\tvar query:CriteriaQuery = cb.createQuery(DelayedClasses);\n");
        out.write("\t\t\t\tquery.from(DelayedClasses);\n");
        out.write("\t\t\t\tvar tq:Query = em.createTypedQuery(query);\n");
        out.write("\t\t\t\tvar res:Array = tq.getResultList() as Array;\n");
        out.write("\t\t\t\tfor each (var delayed:DelayedClasses in res) {\n");
        out.write("\t\t\t\t\tvar delayedClass:Class = getDefinitionByName(delayed.DelayedClass) as Class;\n");
        out.write("\t\t\t\t\tvar service:Object = new delayedClass();\n");
        out.write("\t\t\t\t\tservice.launchDelayedServices()\n");
        out.write("\t\t\t\t\tem.remove(delayed);\n");
        out.write("\t\t\t\t}\n");
        out.write("\t\t\t}\n");
        out.write("\t\t}\n");




    }
}
